#include <pthread.h>
#include <sys/time.h>
#include <stdint.h>
#include "util_alive_check.h"

#define ALIVE_INIT_FLAG (0xA5A5A5A5)

// 计算时间差，考虑u32计数轮回
#define DIFF_SEC(new, old) ((new) > (old) ? (new - old) : (UINT32_MAX + new - old))

// 保存所有被监控的对象
static alive_conf_t g_alive_conf = {0};

// 锁用于互斥访问
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;

// 获得当前时刻的秒数
static unsigned int alive_check_getsec(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec;
}

// 将秒转换为字符串格式的时间
static void alive_check_sec2timestr(unsigned int seconds, char *timestr)
{
    struct tm *timeinfo;
    time_t rawtime = (time_t)seconds; // 将unsigned int转换为time_t

    // 将秒数转换为本地时间
    timeinfo = localtime(&rawtime);

    // 格式化时间字符串为YYYY-MM-DD hh-mm-ss
    snprintf(timestr, 20, "%04d-%02d-%02d %02d:%02d:%02d",
             timeinfo->tm_year + 1900, // 年份从1900年开始计算，需要加上1900
             timeinfo->tm_mon + 1,     // 月份从0开始，需要加1
             timeinfo->tm_mday,
             timeinfo->tm_hour,
             timeinfo->tm_min,
             timeinfo->tm_sec);
}

// 放在一个周期运行的循环里面，比如看门狗线程
// second必须是一个顺序变化的数,建议1秒变化1
void alive_check_items(unsigned int second)
{
    int i = 0;
    unsigned int curr_heart, last_heart, check_period, curr_sec;
    alive_item_t *p_item = NULL;
    ALIVE_STATE_E curr_state;
    p_item = g_alive_conf.items;
    // 取出被监控的每一个对象,检查是否心跳停止
    for (i = 0; i < g_alive_conf.cnt; i++)
    {
        // 被监控对象当前心跳
        curr_heart = p_item->curr_heart_cnt;
        // 被监控对象上次心跳
        last_heart = p_item->last_heart_cnt;
        // 被监控对象的检测周期
        check_period = p_item->check_period;

        curr_state = p_item->state;
        if (check_period && (second % check_period) == 0)
        {
            curr_sec = alive_check_getsec();
            if (curr_heart == last_heart) // 心跳停止
            {
                switch (curr_state)
                {
                case STATE_INIT:
                    p_item->total_init_sec += DIFF_SEC(curr_sec, p_item->last_sec);
                    break;

                case STATE_ALIVE:
                    if (p_item->type == TYPE_HAS_DEADING)
                    {
                        // 被监控对象进入濒死状态,给断开设备一个重连恢复时间
                        p_item->state = STATE_DEADING;
                        p_item->total_deading_cnt++;
                        break;
                    } // TYPE_NO_DEADING没有DEADING状态，如果心跳停止，直接进入到死亡状态

                case STATE_DEADING:
                    p_item->state = STATE_DEAD;
                    // 记录下被监控对象最近死亡的时间
                    p_item->last_dead_sec_arr[(p_item->total_dead_cnt) % ALIVE_CHECK_DEAD_LEN] = curr_sec;
                    // 被监控对象死亡状态增1
                    p_item->total_dead_cnt++;
                    break;

                case STATE_DEAD:
                    // 被监控对象死亡时间增加
                    if (p_item->last_state == STATE_DEAD)
                    {
                        p_item->total_dead_sec += DIFF_SEC(curr_sec, p_item->last_sec);
                    }
                    break;
                default:
                    break;
                }
            }
            else // 心跳恢复跳动 或 心跳正常跳动
            {
                switch (curr_state)
                {
                case STATE_ALIVE:
                    // 被监控对象活动时间增加
                    if (p_item->last_state == STATE_ALIVE)
                    {
                        p_item->total_alive_sec += DIFF_SEC(curr_sec, p_item->last_sec);
                    }
                    break;
                case STATE_INIT:
                // 被监控对象结束INIT状态，开始真正活动起来
                case STATE_DEADING:
                // 被监控对象退出濒死状态
                case STATE_DEAD:
                    p_item->state = STATE_ALIVE;
                    break;

                default:
                    break;
                }
            }
            // 更新被监控对象上一次心跳时间
            p_item->last_heart_cnt = curr_heart;
            // 保存上一次的时间
            p_item->last_sec = curr_sec;
            // 保存上一次的状态信息
            p_item->last_state = curr_state;
        }
        p_item++;
    }
    return;
}

// 初始化该模块,可以指定打印函数,方便接入外部日志系统,为空默认为printf
void alive_check_init(print_func_t print)
{
    if (g_alive_conf.inited != ALIVE_INIT_FLAG)
    {
        memset(g_alive_conf.items, 0x00, sizeof(g_alive_conf.items));
        g_alive_conf.inited = ALIVE_INIT_FLAG;
        g_alive_conf.cnt = 0;
        g_alive_conf.print = (print == NULL) ? printf : print;
    }
}

// 添加被监控对象,period为该监控对象的检测周期,返回值为该被监控对象的索引值
int alive_check_add(const char *item_name, int period, ALIVE_TYPE_E type)
{
    int i = 0, ret = 0;
    alive_item_t *p_item = g_alive_conf.items;

    if (g_alive_conf.inited != ALIVE_INIT_FLAG)
    {
        return -1;
    }

    pthread_mutex_lock(&g_lock);

    for (i = 0; i < ALIVE_CHECK_MAX_ITEM; i++)
    {
        // 查看是否已经添加
        if (p_item->check_period && strcmp(p_item->name, item_name) == 0)
        {
            g_alive_conf.print("alive check : %s already add\n", item_name);
            ret = -1;
            break;
        }

        // 添加新的项
        if (p_item->check_period == 0)
        {
            memcpy(p_item->name, item_name, MAX_LEN - 1);
            p_item->check_period = period;
            p_item->last_sec = alive_check_getsec();
            p_item->type = type;
            g_alive_conf.cnt++;
            ret = i;
            break;
        }
        p_item++;
    }

    pthread_mutex_unlock(&g_lock);

    if (i == ALIVE_CHECK_MAX_ITEM)
    {
        g_alive_conf.print("alive check : no free space\n");
        ret = -1;
    }
    return ret;
}

// 打印某个被监控对象的状态信息
static void alive_check_print_state(int item_idx)
{
    int i, j = 0, total;
    alive_item_t *p_item = NULL;
    char *state_names[] = {"STATE_INIT", "STATE_ALIVE", "STATE_DEAD", "STATE_DEADING"};
    char timestr[64];

    if (g_alive_conf.inited != ALIVE_INIT_FLAG || item_idx >= g_alive_conf.cnt)
    {
        return;
    }
    p_item = &g_alive_conf.items[item_idx];

    g_alive_conf.print("\nitem name : %s\n", p_item->name);
    g_alive_conf.print("current state : %s, last state : %s\n", state_names[p_item->state], state_names[p_item->last_state]);
    g_alive_conf.print("total init seconds : %u\n", p_item->total_init_sec);
    g_alive_conf.print("total alive seconds : %u\n", p_item->total_alive_sec);
    g_alive_conf.print("total dead seconds : %u\n", p_item->total_dead_sec);
    g_alive_conf.print("total dead count : %u\n", p_item->total_dead_cnt);
    if (p_item->type == TYPE_HAS_DEADING)
    {
        g_alive_conf.print("total deading count : %u\n", p_item->total_deading_cnt);
    }
    g_alive_conf.print("total check period : %u\n", p_item->check_period);

    // 总的记录的死亡状态次数
    total = (p_item->total_dead_cnt < ALIVE_CHECK_DEAD_LEN) ? p_item->total_dead_cnt : ALIVE_CHECK_DEAD_LEN;
    // 按时间先后打印出被监控对象死亡的时间
    for (i = 0; i < total; i++)
    {
        j = (p_item->total_dead_cnt - 1 - i) % ALIVE_CHECK_DEAD_LEN;
        j = (j < 0) ? (ALIVE_CHECK_DEAD_LEN - 1) : j;
        alive_check_sec2timestr(p_item->last_dead_sec_arr[j], timestr);
        g_alive_conf.print("dead at : %s\n", timestr);
    }
    g_alive_conf.print("\n");
}

// 打印某个或所有被监控对象的状态信息,当输入为NULL时打印所有的被监控对象信息
void alive_check_print_states(char *item_name)
{
    int i;
    if (g_alive_conf.inited != ALIVE_INIT_FLAG)
    {
        return;
    }

    for (i = 0; i < g_alive_conf.cnt; i++)
    {
        if (item_name) // 打印单个监控对象
        {
            if (strcmp(g_alive_conf.items[i].name, item_name) == 0)
            {
                alive_check_print_state(i);
            }
            return;
        }
        else // 打印所有监控对象
        {
            alive_check_print_state(i);
        }
    }
}

// 获取指定名字的被监控对象的状态信息
int alive_check_get_state(char *item_name, alive_item_t *item)
{
    int i;
    alive_item_t *p_item = NULL;
    p_item = g_alive_conf.items;

    if (g_alive_conf.inited != ALIVE_INIT_FLAG)
    {
        return -1;
    }

    if (item_name != NULL)
    {
        for (i = 0; i < g_alive_conf.cnt; i++)
        {
            if (strcmp(p_item[i].name, item_name) == 0)
            {
                memcpy(item, p_item + i, sizeof(alive_item_t));
                return 0;
            }
        }
    }
    return -1;
}

// 需要添加在被监控的对象正常运行的流程中,index为被监控对象的索引值
void alive_check_beat(int index)
{
    if (g_alive_conf.inited != ALIVE_INIT_FLAG)
    {
        return;
    }
    g_alive_conf.items[index].curr_heart_cnt++;
}